package com.zc.demo.xmlparser;

import org.aspectj.lang.annotation.AdviceName;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import java.io.*;

/**
 * sax解析xml
 * Created by zhangchi9 on 2016/12/12.
 */
public class SaxParser implements XmlDocument {
    private String fileName;
    private StringBuffer buffer = new StringBuffer();
    private String key;

    public SaxParser() {
        this.fileName = "D:\\sax.xml";
    }

    @Override
    public void parseXml(String xml) {
        SAXParserFactory saxfac = SAXParserFactory.newInstance();
        try {
            SAXParser saxparser = saxfac.newSAXParser();
            InputStream is = new FileInputStream(fileName);
            saxparser.parse(is, new MySAXHandler());
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class MySAXHandler extends DefaultHandler {
        boolean hasAttribute = false;
        Attributes attributes = null;

        public void startDocument() throws SAXException {
            System.out.println("文档开始打印了");
            System.out.println("<xml version=\"1.0\" encoding=\"utf-8\"?>");
        }

        public void endDocument() throws SAXException {
            System.out.println("文档打印结束了");
        }

        public void startElement(String uri, String localName, String qName,
                                 Attributes attributes) throws SAXException {
            buffer.delete(0, buffer.length());
            //key = localName;
            key = qName;

            System.out.print("<" + key);
            for (int i = 0; i < attributes.getLength(); i++) {
                String attrName = attributes.getLocalName(i);
                String attrValue = attributes.getValue(i);
                System.out.println(" " + attrName + "=" + attrValue);
            }
            System.out.println(">");
        }

        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            if (key.equals(qName)) {
                System.out.println(buffer); // 输出标记中间的内容
            }
            System.out.println("</" + qName + ">");
        }

        public void characters(char[] ch, int start, int length)
                throws SAXException {
            buffer.append(ch, start, length); // 添加标记中间的内容
        }
    }


    @Override
    public String assembleXml() {
        String xmlStr = null;
        try {
            Result resultXml = new StreamResult(new FileOutputStream(fileName));
            StringWriter writerStr = new StringWriter();
            //SAXTransformerFactory类扩展了 TransformerFactory 以提供特定于 SAX 的工厂方法
            SAXTransformerFactory sff = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
            TransformerHandler th = sff.newTransformerHandler();
            Transformer transformer = th.getTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            //设置与用于转换的此 TransformerHandler 关联的 Result。
            th.setResult(resultXml);
            //接收文档的开始的通知。在其他任何事件回调（不包括 setDocumentLocator）之前，SAX 解析器仅调用此方法一次。
            th.startDocument();
            String four = "\n    ";
            String eight = "\n        ";

            AttributesImpl attr = new AttributesImpl();
            //接收元素开始的通知。
            th.startElement("", "country", "country", attr);
            /**
             * 接收字符数据的通知。析器将调用此方法来报告字符数据的每个存储块。SAX 解析器能够用单个存储块返回所有的连续字符数据，
             * 或者可以将该数据拆分成几个存储块；但是，任何单个事件中的全部字符都必须来自同一个外部实体，以便定位器能够提供有用的信息。
             */
            th.characters(four.toCharArray(), 0, four.length());
            th.startElement("", "china", "china", attr);

            th.characters(eight.toCharArray(), 0, eight.length());
            th.startElement("", "city", "city", attr);

            String bj = "Beijing";
            th.characters(bj.toCharArray(), 0, bj.length());
            //接收元素结束的通知。
            th.endElement("", "city", "city");

            th.characters(eight.toCharArray(), 0, eight.length());

            th.startElement("", "city", "city", attr);
            String sh = "Shanghai";
            th.characters(sh.toCharArray(), 0, sh.length());
            th.endElement("", "city", "city");

            th.characters(four.toCharArray(), 0, four.length());

            th.endElement("", "china", "china");
            th.endElement("", "country", "country");
            th.endDocument();
            xmlStr = writerStr.getBuffer().toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
        return xmlStr;
    }

}
